﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GameNod
{
    class GameNode
    {
        private int x;
        private int y;

        public int X
        {
            get { return x; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException();
                x = value;
            }
        }
        public int Y
        {
            get { return y; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException();
                y = value;
            }
        }

        public GameNode(int posiyionX, int positionY)
        {
            X = posiyionX;
            Y = positionY;
        }




        public void MoveUp()
        {
            Y--;
        }

        public void MoveDown()
        {
            Y++;
        }

        public void MoveLeft()
        {
            X--;
        }
        public void MoveRight()
        {
            X++;
        }

        public bool IsOnPosition(int positionX, int positionY)
        {
                if (X != positionX && Y != positionY)
                    return true;
            return false;
        }

        public virtual void Move(Func<int, int, Position> position)
        {
            Random rnd = new Random();
            switch (rnd.Next(1, 5))
            {
                case 1:
                    {
                        if (position(X, Y - 1) == Position.Free)
                        //IsOnField(node.X, node.Y - 1) && CrossNodes(node.X, node.Y - 1))
                        {
                            MoveUp();
                        }
                        break;
                    }
                case 2:
                    {
                        if (position(X, Y + 1) == Position.Free)
                        //IsOnField(node.X, node.Y + 1) && CrossNodes(node.X, node.Y + 1))
                        {
                            MoveDown();
                        }
                        break;
                    }
                case 3:
                    {
                        if (position(X - 1, Y) == Position.Free)
                        //IsOnField(node.X - 1, node.Y) && CrossNodes(node.X - 1, node.Y))
                        {
                            MoveLeft();
                        }
                        break;
                    }
                case 4:
                    {
                        if (position(X + 1, Y) == Position.Free)
                        //IsOnField(node.X + 1, node.Y) && CrossNodes(node.X + 1, node.Y))
                        {
                            MoveRight();
                        }
                        break;
                    }

            }
        }
    }

    class ConsoleNode: GameNode
    {
        protected Direction move = Direction.OnStart;
        public ConsoleColor ColorNode { get; private set; }
        public char GameNodeSymbol { get; private set; }

        public ConsoleNode(int positionX, int positionY, ConsoleColor color)
            : base(positionX, positionY)
        {
            ColorNode = color;
        }

        public ConsoleNode(int positionX, int positionY, ConsoleColor color, char nodeSymbol)
            : base(positionX, positionY)
        {
            ColorNode = color;
            GameNodeSymbol = nodeSymbol;
        }

        private bool CheckIWasHere(int x, int y, List<GameNode> usedCoordinates)
        {
            foreach (var node in usedCoordinates)
            {
                if (node.X == x && node.Y == y)
                    return true;
            }
            return false;
        }

        protected bool IsOnTop(Func<int, int, Position> position)
        {
            if (position(X, Y - 1) == Position.Border)
                return true;
            return false;
        }
        protected bool IsOnLeftBorder(Func<int, int, Position> position)
        {
            if (position(X - 1, Y) == Position.Border)
                return true;
            return false;
        }
        protected bool IsOnDown(Func<int, int, Position> position)
        {
            if (position(X, Y + 1) == Position.Border)
                return true;
            return false;
        }
        protected bool IsOnRightBorder(Func<int, int, Position> position)
        {
            if (position(X + 1, Y) == Position.Border)
                return true;
            return false;
        }
        protected void MoveOnStart(Func<int, int, Position> position)
        {
            if ((!IsOnTop(position) || !IsOnLeftBorder(position)) && (move == Direction.OnStart))
            {
                if (position(X, Y - 1) == Position.Free)
                {
                    MoveUp();
                }
                if (position(X - 1, Y) == Position.Free)
                {
                    MoveLeft();
                }
            }
        }
    }

    class ColumnsNode : ConsoleNode
    {

        public ColumnsNode(int positionX, int positionY, ConsoleColor color, char nodeSymbol)
            : base(positionX, positionY, color, nodeSymbol)
        {

        }
        public override void Move(Func<int, int, Position> position)
        {
            MoveOnStart(position);
            if (IsOnTop(position) && IsOnLeftBorder(position) && (move == Direction.OnStart))
                move = Direction.Down;
            if (!IsOnDown(position) && (move == Direction.Down))
            {
                if (position(X, Y + 1) == Position.Free)
                {
                    MoveDown();
                }
            }
            else if ((position(X + 1, Y) == Position.Free) && (move == Direction.Down))
            {
                if (position(X + 1, Y) == Position.Free)
                {
                    MoveRight();
                    move = Direction.Up;
                }
            }
            if (!IsOnTop(position) && (move == Direction.Up))
            {
                if (position(X, Y - 1) == Position.Free)
                {
                    MoveUp();
                }
            }
            else if (IsOnTop(position) && (move == Direction.Up))
            {
                if (position(X + 1, Y) == Position.Free)
                {
                    MoveRight();
                    move = Direction.Down;
                }  
            }
        }
    }

    class StringsNode : ConsoleNode
    {

        public StringsNode(int positionX, int positionY, ConsoleColor color, char nodeSymbol)
            : base(positionX, positionY, color, nodeSymbol)
        {

        }
        public override void Move(Func<int, int, Position> position)
        {
            MoveOnStart(position);
            if (IsOnTop(position) && IsOnLeftBorder(position) && (move == Direction.OnStart))
                move = Direction.Right;
            if (!IsOnRightBorder(position) && (move == Direction.Right))
            {
                if (position(X + 1, Y) == Position.Free)
                {
                    MoveRight();
                }
            }
            else if (IsOnRightBorder(position) && (move == Direction.Right))
            {
                if (position(X, Y + 1) == Position.Free)
                {
                    MoveDown();
                    move = Direction.Left;
                }
            }
            if (!IsOnLeftBorder(position) && (move == Direction.Left))
            {
                if (position(X - 1, Y) == Position.Free)
                {
                    MoveLeft();
                }
            }
            else if (IsOnLeftBorder(position) && (move == Direction.Left))
            {
                if (position(X, Y + 1) == Position.Free)
                {
                    MoveDown();
                    move = Direction.Right;
                }
            }
        }
     }

    class SpiralNode : ConsoleNode
    {
        private int height = 0;
        private int wildth = 0;
        private int counter = 0;
        private int v = 0;

        public SpiralNode(int positionX, int positionY, ConsoleColor color, char nodeSymbol)
            : base(positionX, positionY, color, nodeSymbol)
        {

        }
        public override void Move(Func<int, int, Position> position)
        {
            if ((!IsOnTop(position) || !IsOnLeftBorder(position)) && (move == Direction.OnStart))
            {
                if (position(X, Y - 1) == Position.Free)
                {
                    MoveUp();
                }
                if (position(X - 1, Y) == Position.Free)
                {
                    MoveLeft();
                }
                if (!CanIGo(position))
                {
                    MoveDown();
                    MoveRight();
                }

            }
            if ((IsOnTop(position) && IsOnLeftBorder(position)) && (move == Direction.OnStart))
            {
                move = Direction.Down;
            }
            if (!IsOnDown(position) && (wildth == 0) && (move == Direction.Down))
            {
                if (position(X, Y + 1) == Position.Free)
                {
                    MoveDown();
                    v++;
                }
                if (!CanIGo(position))
                {
                    MoveDown();
                    MoveRight();
                }
            }
            else if (IsOnDown(position) && (wildth == 0) && (move == Direction.Down))
            {
                move = Direction.Right;
            }
            if (!IsOnRightBorder(position) && (height == 0) && (move == Direction.Right))
            {
                if (position(X + 1, Y) == Position.Free)
                {
                    MoveRight();
                    wildth++;
                }
                if (!CanIGo(position))
                {
                    MoveDown();
                    MoveRight();
                }
            }
            else if (IsOnRightBorder(position) && (height == 0) && (move == Direction.Right))
            {
                    move = Direction.Up;
                    height = v;
                    v = 0;
            }

            if ((v < (height - counter) && !IsOnTop(position)) && (move == Direction.Up))
            {
                if (position(X, Y - 1) == Position.Free)
                {
                    MoveUp();
                    v++;
                }
                if (!CanIGo(position))
                {
                    MoveDown();
                    MoveRight();
                }
            }
            else if ((v == (height - counter) && IsOnTop(position)) && (move == Direction.Up))
            {
                    move = Direction.Left;
                    v = 0;
            }
            if ((v < (wildth - counter) && !IsOnLeftBorder(position)) && (move == Direction.Left))
            {
                if (position(X - 1, Y) == Position.Free)
                {
                    MoveLeft();
                    v++;
                }
                if (!CanIGo(position))
                {
                    MoveDown();
                    MoveRight();
                }
            }
            else if ((v == (wildth - counter) && IsOnLeftBorder(position)) && (move == Direction.Left))
            {
                if (position(X + 1, Y) == Position.Free)
                {
                    move = Direction.Down;
                    counter = counter + 1;
                    v = 0;
                    MoveRight();
                }
            }

            if ((v < (height - counter) && !IsOnDown(position)) && (move == Direction.Down))
            {
                if (position(X, Y + 1) == Position.Free)
                {
                    MoveDown();
                    v++;
                }
                if (!CanIGo(position))
                {
                    MoveDown();
                    MoveRight();
                }
            }
            else if ((v == (height - counter) && !IsOnDown(position)) && (move == Direction.Down))
            {
                move = Direction.Right;
                v = 0;
            }
            if ((v < (wildth - (counter + 1)) && !IsOnRightBorder(position)) && (move == Direction.Right))
            {
                if (position(X + 1, Y) == Position.Free)
                {
                    MoveRight();
                    v++;
                }
                if (!CanIGo(position))
                {
                    MoveDown();
                    MoveRight();
                }
            }
            else if ((v == (wildth - (counter + 1)) && !IsOnRightBorder(position)) && (move == Direction.Right))
            {
                move = Direction.Up;
                v = 0;
            }
        }

        public bool CanIGo(Func<int, int, Position> position)
        {
            if ((position(X + 1, Y) != Position.Free) && (position(X - 1, Y) != Position.Free)
                    && (position(X, Y + 1) != Position.Free) && (position(X, Y - 1) != Position.Free))
                return false;
            return true;
        }
    }

    enum Direction
    {
        Up,
        Down,
        Left,
        Right,
        OnStart
    }
}

